// SPDX-FileCopyrightText: Adam Evyčędo
//
// SPDX-License-Identifier: AGPL-3.0-or-later

package traffic

import (
	"apiote.xyz/p/szczanieckiej/transformers"

	"bufio"
	"encoding/csv"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"

	"golang.org/x/text/transform"
)

type BerlinVbb struct {
	client http.Client
}

func (BerlinVbb) getTimezone() *time.Location {
	l, _ := time.LoadLocation("Europe/Berlin")
	return l
}

func (BerlinVbb) ConvertVehicles() ([]Vehicle, error) {
	return []Vehicle{}, nil
}

func (BerlinVbb) GetVersions(date time.Time, timezone *time.Location) ([]Version, error) {
	versions := []Version{}
	version, err := MakeVersionTimezone("00010101_99991231", timezone)
	if err != nil {
		return nil, err
	}
	version.Link = "https://www.vbb.de/fileadmin/user_upload/VBB/Dokumente/API-Datensaetze/gtfs-mastscharf/GTFS.zip"
	versions = append(versions, version)
	return versions, nil
}

func (BerlinVbb) String() string {
	return "berlin_vbb"
}

func (BerlinVbb) RealtimeFeeds() map[RealtimeFeedType]string {
	return map[RealtimeFeedType]string{}
}

func (BerlinVbb) Transformer() transform.Transformer {
	return transform.Chain(transformers.TransformerDE, transformers.TransformerPL, transformers.TransformerFR)
}

func (BerlinVbb) Name() string {
	return "Berlin/Brandenburg VBB"
}

func (BerlinVbb) Flags() FeedFlags {
	return FeedFlags{
		Headsign:     HeadsignTripHeadsing,
		StopIdFormat: "{{stop_id}}_{{platform_code}}",
		StopName:     "{{stop_name}} | {{platform_code}}", // TODO platform_code might not be present, but currently templating doesn’t support this
		LineName:     "{{route_short_name}}",
	}
}

func (BerlinVbb) FeedPrepareZip(path string) error {
	// TODO remove or fix zones

	// NOTE add platform codes from stop_id
	stopsFile, err := os.Open(filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while opening stops file: %w", err)
	}
	defer stopsFile.Close()
	stops2File, err := os.OpenFile(filepath.Join(path, "stops2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening stops2 file: %w", err)
	}
	defer stops2File.Close()
	r := csv.NewReader(bufio.NewReader(stopsFile))
	w := csv.NewWriter(stops2File)
	header, err := r.Read()
	if err != nil {
		return fmt.Errorf("while reading stops header: %w", err)
	}
	fields := map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing stops header: %w", err)
	}
	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a stop record: %w", err)
		}
		f, ok := fields["location_type"]
		if (!ok || record[f] == "" || record[f] == "0") && record[fields["platform_code"]] == "" {
			stopID := strings.Split(record[fields["stop_id"]], ":")
			if len(stopID) >= 5 {
				record[fields["platform_code"]] = stopID[4]
			}
		}
		err = w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing a stop record: %w", err)
		}
	}
	w.Flush()
	err = os.Remove(filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while removing stops: %w", err)
	}
	err = os.Rename(filepath.Join(path, "stops2.txt"), filepath.Join(path, "stops.txt"))
	if err != nil {
		return fmt.Errorf("while renaming stops: %w", err)
	}

	// NOTE fix route types
	routesFile, err := os.Open(filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while opening routes file: %w", err)
	}
	defer routesFile.Close()
	routes2File, err := os.OpenFile(filepath.Join(path, "routes2.txt"), os.O_RDWR|os.O_CREATE, 0644)
	if err != nil {
		return fmt.Errorf("while opening routes2 file: %w", err)
	}
	defer routes2File.Close()
	r = csv.NewReader(bufio.NewReader(routesFile))
	w = csv.NewWriter(routes2File)
	header, err = r.Read()
	if err != nil {
		return fmt.Errorf("while reading routes header: %w", err)
	}
	fields = map[string]int{}
	for i, headerField := range header {
		fields[headerField] = i
	}
	err = w.Write(header)
	if err != nil {
		return fmt.Errorf("while writing routes header: %w", err)
	}

	for {
		record, err := r.Read()
		if err == io.EOF {
			break
		}
		if err != nil {
			return fmt.Errorf("while reading a route record: %w", err)
		}
		if record[fields["route_type"]] == "100" {
			record[fields["route_type"]] = "2"
		}
		if record[fields["route_type"]] == "109" {
			record[fields["route_type"]] = "1"
		}
		if record[fields["route_type"]] == "400" {
			record[fields["route_type"]] = "1"
		}
		if record[fields["route_type"]] == "700" {
			record[fields["route_type"]] = "3"
		}
		if record[fields["route_type"]] == "900" {
			record[fields["route_type"]] = "0"
		}
		if record[fields["route_type"]] == "1000" {
			record[fields["route_type"]] = "4"
		}
		err = w.Write(record)
		if err != nil {
			return fmt.Errorf("while writing a route record: %w", err)
		}
	}
	w.Flush()
	err = os.Remove(filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while removing routes: %w", err)
	}
	err = os.Rename(filepath.Join(path, "routes2.txt"), filepath.Join(path, "routes.txt"))
	if err != nil {
		return fmt.Errorf("while renaming routes: %w", err)
	}
	return nil
}

func (BerlinVbb) QRInfo() (string, QRLocation, string) {
	return "qr.bvg.de", QRLocationPath, "/(?<SEL>.*)"
}
